<script lang='ts'>
import { AxiosResponse } from "axios"
import { ElLoading } from "element-plus"
import {
  defineComponent,
  PropType,
  reactive,
  ref,
  watch,
  getCurrentInstance,
  onMounted
} from "vue"
import {
  PageTableExpose,
  SortChangeType,
  SortInfoType,
  VmsPageTableColumn
} from "./interface"
import {
  downloadFile,
  queryParamHandler,
  sortOrderTransform,
  tableColumnHandler,
  tableHeightFit
} from "./util"
import emptyImg from "/@/assets/img/emptyStatus.png"

export default defineComponent({
  name: "JxtechPageTable"
})
</script>

<script lang='ts' setup>
const props = defineProps({
  headerType: {
    type: String
  },
  // 分页器显示隐藏
  paginationShow: {
    type: Boolean,
    default: true
  },
  // 下载按钮显示隐藏
  downloadShow: {
    type: Boolean,
    default: true
  },
  //参见 element-plus
  rowKey: {
    type: [String, Function],
    required: true
  },
  // 表格的高度适配方式 auto full height
  fit: {
    type: String,
    default: "auto"
  },
  // 表格高度
  tableHeight: {
    type: [String, Number],
    default: "auto"
  },
  /**
   * 斑马纹
   */
  stripe: {
    type: Boolean,
    default: true
  },
  /**
   * 设置表格大小
   */
  size: {
    type: String,
    default: "small"
  },
  /**
   * 边框
   */
  border: {
    type: Boolean,
    default: true
  },
  /**
   * 默认排序
   */
  defaultSort: Object,
  /**
   * 表格数据 静态数据
   */
  tableData: Array as PropType<any[]>,
  /**
   * 列配置
   */
  tableColumn: {
    type: Array as PropType<VmsPageTableColumn[]>,
    required: true
  },
  /**
   * 加载数据
   */
  loadData: {
    type: Function,
    required: true
  },
  /**
   * 导出
   */
  expData: {
    type: Function
  },
  //高亮当前行
  highlightCurrentRow: {
    type: Boolean,
    default: true
  },
  /////分页参数
  pageSize: {
    type: Number,
    default: 25
  },
  /**
   * 设置列的状态
   */
  tableRowClassName: Function
})

const emit = defineEmits<{
  (e: "selection-change", selectData: any[], selectPkList: string[]): void //行选择事件
  (e: "row-click", row: any, column: any, event: Event): void //行点击事件
  (e: "row-dblclick", row: any, column: any, event: Event): void //行双击事件
}>()

//获取组件插槽
const slots = getCurrentInstance()?.slots
let jxtechPageTableWrapperRef = ref()
const JxtechPageTableRef = ref()

const JxtechPageTableState = reactive({
  loading: false,
  tableData: props.tableData,
  tableColumn: props.tableColumn,
  isFullscreen: false,
  //筛选信息
  filterInfo: {} as any,
  //存储排序信息
  sortInfo: {} as SortInfoType,
  //存放排序列prop 与自定义排序字段的映射
  sortMappingMap: new Map() as Map<string, string>,
  //选中的数据
  selectionData: [] as any[],
  //选中的数据组件集合
  selectionPkList: [] as string[],
  /**
   * 处理序号
   */
  indexHandler: (index: number) => {
    return (
      (paginationState.currentPage - 1) * paginationState.currentPageSize +
      index +
      1
    )
  },
  /**
   * 当列渲染成链接时 点击触发linkClick事件
   */
  linkClick: (row: any, column: VmsPageTableColumn) => {
    if (column.linkClick) column.linkClick(row, column)
  },
  //表格筛选后触发
  filterChange: (filters: any) => {
    //这里时当前变化列的对象 key是当前列的columnKey value是选中的数组 单选和多选一样
    for (let key in filters) {
      JxtechPageTableState.filterInfo[key] = filters[key]
    }
    pageTableExpose.loadTable()
  },
  //表格排序后触发
  sortChange: (item: SortChangeType) => {
    if (item.prop && item.order) {
      JxtechPageTableState.sortInfo = {
        property:
          JxtechPageTableState.sortMappingMap.get(item.prop) || item.prop,
        direction: sortOrderTransform(item.order)
      }
    } else {
      JxtechPageTableState.sortInfo = { property: null, direction: null }
    }
    pageTableExpose.loadTable()
  },
  selectionChange: (selectData: any[]) => {
    const pkList: string[] = []
    if (selectData && selectData.length > 0) {
      selectData.forEach(item => {
        pkList.push(
          item[
            props.rowKey instanceof Function ? props.rowKey(item) : props.rowKey
          ]
        )
      })
    }
    JxtechPageTableState.selectionData = selectData
    JxtechPageTableState.selectionPkList = pkList
    emit("selection-change", selectData, pkList)
  },
  rowClick: (row: any, column: any, event: Event) => {
    emit("row-click", row, column, event)
  },
  rowDblClick: (row: any, column: any, event: Event) => {
    emit("row-dblclick", row, column, event)
  },
  //导出按钮点击事件
  onExportButtonClick: (type: string) => {
    pageTableExpose.expData(type)
    // if (type == "excel") {
    //     pageTableExpose.expData(type);
    // } else if (type == "csv") {
    //     pageTableExpose.expData(type);
    // } else if (type == "pdf") {
    //     pageTableExpose.expData(type);
    // }
  }
})

/**
 * 分页组件 属性
 */
const paginationState = reactive({
  currentPage: 1,
  currentPageSize: props.pageSize,
  pageSizeArray: [10, 25, 50, 100],
  layout: "total, sizes, prev, pager, next, jumper",
  total: 0,
  handleSizeChange: (pagesize: number) => {
    paginationState.currentPageSize = pagesize
    pageTableExpose.loadTable()
  },
  handleCurrentChange: (page: number) => {
    paginationState.currentPage = page
    pageTableExpose.loadTable()
  }
})

/**
 * 一些工具方法
 */
const pageTableExpose: PageTableExpose = {
  /**
   * 加载表格
   */
  loadTable: async () => {
    JxtechPageTableState.loading = true
    const _queryparam = queryParamHandler(
      paginationState,
      JxtechPageTableState.filterInfo,
      JxtechPageTableState.sortInfo,
      null
    )
    try {
      const res = await props.loadData(_queryparam)
      JxtechPageTableState.tableData = res.data.rows
      paginationState.total = res.data.total
    } catch (err) {
      console.log(err)
    } finally {
      JxtechPageTableState.loading = false
    }
  },
  /**
   * 重载表格
   */
  reloadTable: () => {
    pageTableExpose.clearSelection()
    pageTableExpose.clearSort()
    pageTableExpose.clearFilter()
    pageTableExpose.loadTable()
  },
  /**
   * 导出文件
   */
  expData: (expType?: string) => {
    let loadingText = "下载中..."
    let loadingInstance = ElLoading.service({
      target: ".jxtech-page-table-wrapper",
      lock: true,
      text: loadingText
    })
    if (!expType) expType = "excel"
    let _queryparam = queryParamHandler(
      paginationState,
      JxtechPageTableState.filterInfo,
      JxtechPageTableState.sortInfo,
      null
    )
    if (!props.expData) {
      console.log("请配置 expData 方法")
      return
    }
    if (!_queryparam) _queryparam = {}
    _queryparam.expType = expType
    props
      .expData(_queryparam)
      .then((res: AxiosResponse<Blob>) => {
        const fileBlob = res.data
        if (fileBlob.type == "application/json") {
          let reader = new FileReader()
          reader.readAsText(fileBlob)
          reader.onload = e => {
            console.log("导出异常") //todo 这里后面再优化
          }
          // loadingText = "导出异常 请稍后再试"
        } else {
          var fileName = res.headers["content-disposition"]
            .split(";")[1]
            .split("filename=")[1]
            .replace('"', "")
            .replace('"', "")
          downloadFile(decodeURI(fileName), fileBlob)
        }
      })
      .finally(() => loadingInstance.close())
  },
  /**
   * 获取选择的数据
   */
  getSelectionData: () => {
    return JxtechPageTableState.selectionData
  },
  /**
   * 获取选中的数据的主键集合
   */
  getSelectionPkList: () => {
    return JxtechPageTableState.selectionPkList
  },
  /**
   * 清理选择的数据
   */
  clearSelection: () => {
    JxtechPageTableRef.value.clearSelection()
  },
  /**
   * 清理排序
   */
  clearSort: () => {
    JxtechPageTableRef.value.clearSort()
    //清理sortInfo
    JxtechPageTableState.sortInfo = { property: null, direction: null }
  },
  /**
   * 清理筛选
   * @param filters 需要清理列筛选的prop数组 不穿 则清理所有
   */
  clearFilter: (columnKeyArray?: Array<string>) => {
    if (columnKeyArray && columnKeyArray.length > 0) {
      columnKeyArray.forEach(columnKey => {
        JxtechPageTableRef.value.clearFilter(columnKey)
        //清理的同时我们需要把对应的filterInfo中保存的值清理掉
        JxtechPageTableState.filterInfo[columnKey] = []
      })
    } else {
      JxtechPageTableRef.value.clearFilter()
      for (let key in JxtechPageTableState.filterInfo) {
        JxtechPageTableState.filterInfo[key] = []
      }
    }
  }
}

watch(
  () => props.tableData,
  val => {
    JxtechPageTableState.tableData = val
  }
)

tableColumnHandler(
  JxtechPageTableState.tableColumn,
  JxtechPageTableState.filterInfo,
  JxtechPageTableState.sortMappingMap
)

//设置排序默认值
if (props.defaultSort) {
  JxtechPageTableState.sortInfo = {
    property:
      JxtechPageTableState.sortMappingMap.get(props.defaultSort.prop) ||
      props.defaultSort.prop,
    direction: sortOrderTransform(props.defaultSort.order)
  }
}

// 表格头部事件
const PageTableHeaderToolBarState = reactive({
  onRefreshTable: () => {
    pageTableExpose.reloadTable()
  },
  onDownloadTable: () => {
    pageTableExpose.expData()
  }
})
const jxtechTableFooterRef = ref()
onMounted(() => {
  //适配表格高度
  tableHeightFit(
    JxtechPageTableRef.value,
    jxtechPageTableWrapperRef.value,
    jxtechTableFooterRef.value,
    props.fit,
    props.tableHeight
  )
})
//对外展开那些属性
defineExpose({
  ...pageTableExpose
})
</script>
<template>
  <div class="jxtech-page-table-container">
    <!-- page-table-header-start -->
    <div class="jxtech-page-table-header" :class="slots?.header ? '' : 'header-hidden'">
      <slot name="header"></slot>
    </div>

    <!-- page-table-header-end -->
    <!-- page-table-content-start -->
    <div class="jxtech-page-table-wrapper" ref="jxtechPageTableWrapperRef">
      <el-table v-loading="JxtechPageTableState.loading" ref="JxtechPageTableRef" :data="JxtechPageTableState.tableData"
                element-loading-text="拼命加载中..." :border="border" :stripe="stripe" :size="size" :default-sort="defaultSort"
                :highlight-current-row="highlightCurrentRow" :row-class-name="tableRowClassName" tooltip-effect="light"
                @filter-change="JxtechPageTableState.filterChange" @sort-change="JxtechPageTableState.sortChange"
                @selection-change="JxtechPageTableState.selectionChange" @row-click="JxtechPageTableState.rowClick"
                @row-dblclick="JxtechPageTableState.rowDblClick">
        <template v-for="column in tableColumn">
          <!-- 序号 -->
          <el-table-column v-if="column.type === 'index'" :index="JxtechPageTableState.indexHandler" :type="column.type" :label="column.label"
                           :width="column.width" :align="column.align || 'center'"></el-table-column>

          <!-- 选择列 -->
          <el-table-column v-else-if="column.type === 'selection'" :type="column.type" :label="column.label" :width="column.width"
                           :align="column.align || 'center'"></el-table-column>
          <template v-else>
            <el-table-column :prop="column.prop" :label="column.label" :width="column.width" :align="column.align || 'center'"
                             :columnKey="column.columnKey" :filters="column.filter?.filters"
                             :filter-placement="column.filter?.filterPlacement || 'bottom-start'" :filter-multiple="column.filter?.filterMultiple"
                             :filtered-value="column.filter?.filteredValue" :sortable="column.sort?.sortable"
                             :show-overflow-tooltip="column.showOverflowTooltip">
              <template #default="scope">
                <!-- 渲染链接 -->
                <span class="column-link" v-if="column.type === 'link' && column.prop"
                      @click.stop.prevent="JxtechPageTableState.linkClick(scope.row, column)">{{ scope.row[column.prop] }}</span>
                <!-- 渲染默认数据 -->
                <span v-else-if="!column.slot && column.prop">{{ scope.row[column.prop] }}</span>
                <!-- 渲染插槽 -->
                <slot v-else :name="column.slot" :row="scope.row">{{ column.slot }}</slot>
              </template>
            </el-table-column>
          </template>
        </template>
        <template #empty>
          <el-empty :image-size="240" :image="emptyImg" description="还没有数据录入哦！"></el-empty>
        </template>
      </el-table>
      <!-- page-table-content-end -->
      <!-- page-table-footer-start -->
      <div class="jxtech-page-table-footer" ref="jxtechTableFooterRef">
        <el-pagination v-if="paginationShow" background @size-change="paginationState.handleSizeChange"
                       @current-change="paginationState.handleCurrentChange" :current-page="paginationState.currentPage"
                       :page-sizes="paginationState.pageSizeArray" :page-size="paginationState.currentPageSize" :layout="paginationState.layout"
                       :total="paginationState.total"></el-pagination>
        <div class="jxtech-footer-download-icon" v-if="downloadShow" style="display: none;">
          <span title="CSV下载" @click="JxtechPageTableState.onExportButtonClick('csv')">
            <jxtech-svg-icon icon="#icon-CSV" :size="22" />
          </span>
          <span title="PDF下载" @click="JxtechPageTableState.onExportButtonClick('pdf')">
            <jxtech-svg-icon icon="#icon-PDF" :size="22" />
          </span>

          <span title="EXCEL下载" @click="JxtechPageTableState.onExportButtonClick('excel')">
            <jxtech-svg-icon icon="#icon-ECEL" :size="22" />
          </span>
        </div>
      </div>
      <!-- page-table-footer-end-->
    </div>
  </div>
</template>

<style lang="scss" scoped>
.header-hidden {
  display: none;
}
.column-link {
  color: #0e6fb7;
  cursor: pointer;
  &:hover {
    text-decoration: underline;
  }
}
// ::v-deep(.el-table) {
//     .el-loading-spinner {
//         background: url("/@/assets/img/loading.gif") no-repeat center;
//         background-size: 200px 120px;
//         height: 100%;
//         top: 50px;
//     }
// .circular {
//     display: none;
// }
//     .el-loading-spinner .el-loading-text {
//         margin-top: 130px;
//     }
//     .el-loading-text {
//         color: #eee;
//         transition: all 0.2s;
//     }
// }
::v-deep(.el-table th.el-table__cell > .cell.highlight) {
  color: orange;
}
::v-deep(.el-table .ascending .sort-caret.ascending) {
  border-bottom-color: orange;
}
::v-deep(.el-table__column-filter-trigger i) {
  color: aliceblue;
}
::v-deep(.el-table .descending .sort-caret.descending) {
  border-top-color: orange;
}
.jxtech-page-table-container {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 4px 1px #aec8e3;
  border: 1px solid #e4e7ed;
}
.jxtech-page-table-header {
  background-color: #fff;
  padding: 10px 20px;
  vertical-align: center;
  border-bottom: 2px solid #eaf2f8;
}
::v-deep(.el-table th.el-table__cell) {
  background-color: #0e6fb7;
  color: #fff;
}

.el-card__body {
  padding-top: 0;
}

::v-deep(.el-card__body) {
  padding: 16px;
}
::v-deep(.el-pagination) {
  padding: 10px;
}
.jxtech-page-table-wrapper {
  position: relative;
  background-color: #fff;
  // box-shadow: 0 4px 4px rgba(65, 97, 133, 0.6);
  padding-top: 20px;
  ::v-deep(.el-table) {
    width: calc(100% - 40px);
    margin: 0 20px 20px;
    height: calc(100% - 50px);
    tr {
      height: 30px;
      line-height: 30px;
      th {
        letter-spacing: 0.1em;
        border-top: 1px solid #eaf1f9;
      }
    }
  }

  ::v-deep(.el-table__body-wrapper) {
    overflow-y: auto;
    height: calc(100% - 41px) !important;
  }
  ::v-deep(.el-link--inner) {
    color: #0e6fb7;
    &:hover {
      color: #409eff;
    }
  }
  ::v-deep(tr.el-table__row--striped td.el-table__cell) {
    background-color: #f3f8fb;
  }
  ::v-deep(.el-table--border .el-table__cell) {
    border-color: #d9e5f5;
  }
  ::v-deep(.el-table--border) {
    border: unset;
  }
}
.jxtech-page-table-footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 50px;
  z-index: 9;
  display: flex;
  justify-content: center;
  align-items: center;
  // 分页器的下拉小箭头
  ::v-deep(.el-pagination .el-input__suffix) {
    right: 8px;
  }
  .jxtech-footer-download-icon {
    width: 100px;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: space-around;
    > span {
      cursor: pointer;
      transition: all 0.2s;
      font-size: 22px;

      &:hover {
        font-size: 28px;
        transform: calc(0.9);
      }
    }
  }
  ::v-deep(.number) {
    border: 1px solid #ccc;
    background-color: #fff !important;
  }
  ::v-deep(.active) {
    background-color: #fff !important;
    color: #0e6fb7 !important;
  }
  ::v-deep(.btn-prev) {
    background-color: #fff;
    border: 1px solid #ccc;
  }
  ::v-deep(.btn-next) {
    background-color: #fff;
    border: 1px solid #ccc;
  }
}
// 表格行hover效果
::v-deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {
  background-color: #dbe9f4;
}
// 表格的外边框
// .el-table--border::after,
// .el-table--group::after,
// .el-table::before {
//     content: unset;
// }

// ::v-deep(.el-table__row td:nth-last-child(1)) {
//     border-right: unset;
// }

//2021/1/10 更新element-plus 1.3.3.beta
::v-deep(.el-table__inner-wrapper) {
  height: 100%;
}
</style>